/*
 *  Project:            timelyRV_v1.x -- a RISCV-32IMC SoC.
 *  Module name:        PE_ARRAY.
 *  Description:        This module is used to connect MultiCore_Top with 
 *                       SPI_Config, Pkt_Proc_Top, Peri_Top.
 *  Last updated date:  2022.09.20. (checked)
 *
 *  Communicate with Junnan Li <lijunnan@nudt.edu.cn>.
 *  Copyright (C) 2021-2022 NUDT.
 *
 *  Noted:
 *    1) 134b pkt data definition: 
 *      [133:132] head tag, 2'b01 is head, 2'b10 is tail;
 *      [131:128] valid tag, 4'b1111 means sixteen 8b data is valid;
 *      [127:0]   pkt data, invalid part is padded with x;
 *    2) 168b pkt meta definition: 
 *      [167:152] OutportBM, InportBM;
 *      [151:144] PEBM (PE bitmap), means which PE to process this pkt;
 *      [143:128] BufId;
 *      [127:112] [127:122]: reserved;          [121]: mac lookup enable;
 *                [120]    : mac learn disable; [119]: to DMA; 
 *                [118]    : discard tag;       [117]: TTSE 1588-related; 
 *                [116]    : OSTC 1588-related; [115]: to gen TCP checksum;
 *                [114]    : to check checksum; 
 *                [113:112]: pkt type, i.e., 2’b11 is NACP, 2’b10 is PTP,
 *                                           2’b01 is TCP, 2'b00 is default;
 *      [111:96 ] FlowID;
 *      [95 :88 ] Priority;
 *      [87 :80 ] DMID;
 *      [76 :64 ] pkt length;
 *      [63 :0  ] timestamp;
 *    3) irq for cv32e40p: {irq_fast(Peri), 4'b0, irq_external, 3'b0,  
 *                            irq_timer, 3'b0, irq_software, 3'b0};
 *    4) Space = 2;
 */

  //====================================================================//
  //*   Connection Relationship                                         //
  //*  +-----------+                                +------------+      //
  //*  | PE_Config |--------------------------+     | CMCU_Debug |      //
  //*  +-----------+                          |     +------------+      //
  //*     |    | spi                          | Conf                    //
  //*     |    |   +----------+ <peri   +---------------+               //
  //* pkt |    +---| Peri_Top |---------| MultiCore_top |               //
  //*     |        +----------+ offset> +---------------+               //
  //*  +--------------+                       | DRA/DMA                 //
  //*  | Pkt_Proc_Top |-----------------------+                         //
  //*  +--------------+                                                 //
  //====================================================================//

module PE_ARRAY(
  //======================= clock & resets  ============================//
   input  wire              i_sys_clk
  ,input  wire              i_sys_rst_n
  ,input  wire              i_pe_clk
  ,input  wire              i_rst_n
  ,input  wire              i_spi_clk
  //======================= pkt from/to CPI ============================//
  //* pkt[133:132]: 2'b01 is head, 2'b00 is body, and 2'b10 is tail;
  ,input  wire [      47:0] i_pe_conf_mac
  ,input  wire              i_data_valid
  ,input  wire [     133:0] i_data    
  ,input  wire              i_meta_valid
  ,input  wire [     167:0] i_meta  
  ,output wire              o_alf 
  //* pkt to CPI, TODO,
  ,output wire              o_data_valid
  ,output wire [     133:0] o_data
  ,output wire              o_meta_valid
  ,output wire [     167:0] o_meta
  ,input  wire              i_alf
  //======================= uart            ============================//
  ,(*mark_debug="true"*)input  wire [`NUM_PE-1:0] i_uart_rx
  ,(*mark_debug="true"*)output wire [`NUM_PE-1:0] o_uart_tx
  ,(*mark_debug="true"*)input  wire [`NUM_PE-1:0] i_uart_cts
  ,(*mark_debug="true"*)output wire [`NUM_PE-1:0] o_uart_rts
  
  // //======================= CAN             ============================//
  // //,inout  wire    [`NUM_PE-1:0]  i_can_ad
  //  ,input	wire	[`NUM_PE*8-1:0]           i_can_ad               //modify: ad signal width
  //  ,output    wire        [`NUM_PE*8-1:0]           o_can_ad
  //  ,output    wire        [`NUM_PE-1:0]            o_can_ad_sel
  // ,output wire    [`NUM_PE-1:0]  o_can_cs_n
  // ,output wire    [`NUM_PE-1:0]  o_can_ale_as
  // ,output wire    [`NUM_PE-1:0]  o_can_wr_n
  // ,output wire    [`NUM_PE-1:0]  o_can_rd_n
  // ,output wire    [`NUM_PE-1:0]  o_can_mode
  // ,input  wire    [`NUM_PE-1:0]  i_can_int_n
  //======================= Pads            ============================//
  ,input    wire  [    3:0] i_start_en_pad
);

  //====================================================================//
  //*   internal reg/wire/param declarations
  //====================================================================//
  //* 1-1) Configure info: PE_Config <---> PE's instr/data ram;
  wire                      w_conf_rden, w_conf_wren;
  wire  [           31:0]   w_conf_addr, w_conf_wdata;
  wire  [           31:0]   w_conf_rdata;
  wire  [            3:0]   w_conf_en,   w_start_en;  //* bitmap for 4 PEs;
  //* 1-2) Configure info: Pkt_Proc_Top <---> PE_Config (bypass CMCU)
  wire                      w_data_conf_valid_from_net;
  wire  [           133:0]  w_data_conf_from_net      ;
  wire                      w_data_conf_valid_to_net  ;
  wire  [           133:0]  w_data_conf_to_net        ;
  
  //* 2-1) Peripherals-related: 2 PEs <---> Peripherals Bus (PeriBus);
  wire  [     `NUM_PE-1:0]  w_peri_rden, w_peri_wren;
  wire  [  `NUM_PE*32-1:0]  w_peri_addr, w_peri_wdata;
  wire  [   `NUM_PE*4-1:0]  w_peri_wstrb;
  wire  [  `NUM_PE*32-1:0]  w_peri_rdata;
  wire  [     `NUM_PE-1:0]  w_peri_ready;
  wire  [     `NUM_PE-1:0]  w_peri_gnt;
  //* 2-2) Peripherals-related: PeriBus <---> DMA, DRA;
  //* NUM_PERI_OUT is peris outside of Peri_Top, i.e., DMA, DRA;
  wire  [              `NUM_PE*32-1:0]  w_addr_2peri;
  wire  [   `NUM_PE*`NUM_PERI_OUT-1:0]  w_wren_2peri;
  wire  [   `NUM_PE*`NUM_PERI_OUT-1:0]  w_rden_2peri;
  wire  [              `NUM_PE*32-1:0]  w_wdata_2peri;
  wire  [               `NUM_PE*4-1:0]  w_wstrb_2peri;
  wire  [`NUM_PE*`NUM_PERI_OUT*32-1:0]  w_rdata_2PBUS;
  wire  [   `NUM_PE*`NUM_PERI_OUT-1:0]  w_ready_2PBUS;
  wire  [   `NUM_PE*`NUM_PERI_OUT-1:0]  w_int_2PBUS;
  
  //* 3) Irq-related: 3 PEs <---> irq Bus (IrqBus);
  wire  [  `NUM_PE*32-1:0]  w_irq_bitmap;
  wire  [     `NUM_PE-1:0]  w_irq_ack;
  wire  [   `NUM_PE*5-1:0]  w_irq_id;

  //* 4) Special registers from/to CSR_Peri;
  //* start addresses of Instr/Data for 2 PEs;
  wire  [  `NUM_PE*32-1:0]  w_instr_offset_addr;
  wire  [  `NUM_PE*32-1:0]  w_data_offset_addr;   //* default is 32KB;
  
  //* 6) DRA-related: PE's regs <---> DRA_Engine;
  wire  [     `NUM_PE-1:0]  w_reg_rd;           //* to read data from DRA engine;
  wire  [  `NUM_PE*32-1:0]  w_reg_raddr;        //* addr to read (from PE);
  wire  [           511:0]  w_reg_rdata;        //* return read data from DRA engine;
  wire  [     `NUM_PE-1:0]  w_reg_rvalid;       //* return recv data from DRA engine;
  wire  [     `NUM_PE-1:0]  w_reg_rvalid_desp;  //* return recv desp from DRA engine;
  wire  [     `NUM_PE-1:0]  w_reg_wr, w_reg_wr_desp;
  wire  [  `NUM_PE*32-1:0]  w_reg_waddr;        //* addr to write (from PE);
  wire  [ `NUM_PE*512-1:0]  w_reg_wdata;        //* wdata from PE;
  wire  [  `NUM_PE*32-1:0]  w_status_2core, w_status_2pktMem;

  //* 7) DMA-related: PE's data ram <---> DMA_Engine;
  wire  [     `NUM_PE-1:0]  w_dma_rden;         //* to read/write data SRAM;
  wire  [     `NUM_PE-1:0]  w_dma_wren;
  wire  [  `NUM_PE*32-1:0]  w_dma_addr, w_dma_addr_with_offset;
  wire  [  `NUM_PE*32-1:0]  w_dma_wdata;
  wire  [  `NUM_PE*32-1:0]  w_dma_rdata;        //* return read result from data SRAM;
  wire  [     `NUM_PE-1:0]  w_dma_rvalid;
  wire  [     `NUM_PE-1:0]  w_dma_gnt;          //* allow to read/write next data;

  assign w_dma_addr_with_offset[32*0+:32] = w_dma_addr[0*32+:32] + 
                            {2'b0, w_data_offset_addr[(0*32+31)-:30]};
  // assign w_dma_addr_with_offset[32*1+:32] = w_dma_addr[1*32+:32] + 
                            // {2'b0, w_data_offset_addr[(1*32+31)-:30]};
  //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>//

  //====================================================================//
  //*   MultiCore_top
  //====================================================================//
  MultiCore_Top MultiCore_Top(
    .i_clk                  (i_pe_clk                     ),
    .i_rst_n                (i_rst_n                      ),
    //* conf instr/data mem, connected with CMCU_Config;
    .i_conf_rden            (w_conf_rden                  ),
    .i_conf_wren            (w_conf_wren                  ),
    .i_conf_addr            (w_conf_addr                  ),
    .i_conf_wdata           (w_conf_wdata                 ),
    .o_conf_rdata           (w_conf_rdata                 ),
    .i_conf_en              (w_conf_en                    ),
    //* to peri, connected with Peri_Top;
    .o_peri_rden            (w_peri_rden                  ),
    .o_peri_wren            (w_peri_wren                  ),
    .o_peri_addr            (w_peri_addr                  ),
    .o_peri_wdata           (w_peri_wdata                 ),
    .o_peri_wstrb           (w_peri_wstrb                 ),
    .i_peri_rdata           (w_peri_rdata                 ),
    .i_peri_ready           (w_peri_ready                 ),
    .i_peri_gnt             ({`NUM_PE{1'b1}}              ), 
    //* irq;
    .i_irq_bitmap           (w_irq_bitmap                 ),
    .o_irq_ack              (w_irq_ack                    ),
    .o_irq_id               (w_irq_id                     ),
    //* instr/data offset;
    .i_instr_offset_addr    (0          ),
    .i_data_offset_addr     (0           ),
    //* DRA, connected with Pkt_Proc;
    .o_reg_rd               (w_reg_rd                     ),
    .o_reg_raddr            (w_reg_raddr                  ),
    .i_reg_rdata            (512'b0                       ),
    .i_reg_rvalid           ({`NUM_PE{1'b0}}              ),
    .i_reg_rvalid_desp      ({`NUM_PE{1'b0}}              ),
    .o_reg_wr               (w_reg_wr                     ),
    .o_reg_wr_desp          (w_reg_wr_desp                ),
    .o_reg_waddr            (w_reg_waddr                  ),
    .o_reg_wdata            (w_reg_wdata                  ),
    .i_status               ({(`NUM_PE*32){1'b0}}         ),
    .o_status               (w_status_2pktMem             ),
    //* DMA;
    .i_dma_rden             (w_dma_rden                   ),
    .i_dma_wren             (w_dma_wren                   ),
    .i_dma_addr             (w_dma_addr_with_offset       ),
    .i_dma_wdata            (w_dma_wdata                  ),
    .o_dma_rdata            (w_dma_rdata                  ),
    .o_dma_rvalid           (w_dma_rvalid                 ),
    .o_dma_gnt              (w_dma_gnt                    ),
    //* start_en;
    .i_start_en             (w_start_en                   ),
    .i_rst_n_AiPE           (1'b0                         )
  );
  //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>//

  //====================================================================//
  //*   SPI_Config & Network_Config
  //====================================================================//
    PE_Config PE_Config(
      .i_clk                (i_pe_clk                     ),
      .i_rst_n              (i_rst_n                      ),
      //* configure input, connected with LOCAL_PARSER (cmcu);
      .i_cs                 (1'b1                         ),
      .i_wr_rd              (1'b0                         ),
      .i_address            (20'b0                        ),
      .i_data_in            (32'b0                        ),
      .o_ack_n              (                             ),
      .o_data_out           (                             ),
      //* ethernet's type is 0x9005;
      .i_data_conf_valid    (w_data_conf_valid_from_net   ),
      .i_data_conf          (w_data_conf_from_net         ),
      .o_data_conf_valid    (w_data_conf_valid_to_net     ),
      .o_data_conf          (w_data_conf_to_net           ),
      //* configure by flash (spi);
      .i_conf_wren_spi      (1'b0                         ),
      .i_conf_addr_spi      (32'b0                        ),
      .i_conf_wdata_spi     (32'b0                        ),
      .i_conf_en_spi        (4'hf                         ),
      .i_finish_inilization (1'b1                         ),
      //* configure output, connected with MultiCore;
      .o_conf_rden          (w_conf_rden                  ),
      .o_conf_wren          (w_conf_wren                  ),
      .o_conf_addr          (w_conf_addr                  ),
      .o_conf_wdata         (w_conf_wdata                 ),
      .i_conf_rdata         (w_conf_rdata                 ),
      .o_conf_en            (w_conf_en                    ),
      //* to update system_time by localbus;
      .o_update_valid       (                             ),
      .o_update_system_time (                             )
    );
  //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>//

  //====================================================================//
  //*   Peri_Top  
  //====================================================================//
  //* peri/irq bus, include UARTs, SPI, GPIO, CSR, CSRAM, DMA, dDMA;
  Peri_Top Peri_Top(
    //* clk & rst_n;
    .i_pe_clk               (i_pe_clk                     ),
    .i_rst_n                (i_rst_n                      ),
    .i_spi_clk              (i_spi_clk                    ),
    .i_sys_clk              (i_sys_clk                    ),
    .i_sys_rst_n            (i_sys_rst_n                  ),
    //* UART
    .o_uart_tx              (o_uart_tx                    ),
    .i_uart_rx              (i_uart_rx                    ),
    .i_uart_cts             (i_uart_cts                   ),   
  //   //* CAN
  //  // .i_can_ad               (i_can_ad                     ),
  //  .i_can_ad               (i_can_ad                     ),
  //      .o_can_ad               (o_can_ad                     ),
  //      .o_can_ad_sel           (o_can_ad_sel                 ),
  //   .o_can_cs_n             (o_can_cs_n                   ),
  //   .o_can_ale_as           (o_can_ale_as                 ),
  //   .o_can_wr_n             (o_can_wr_n                   ),
  //   .o_can_rd_n             (o_can_rd_n                   ),
  //   .o_can_mode             (o_can_mode                   ),
  //   .i_can_int_n            (i_can_int_n                  ),
    //* DMA, DRA, connected with MultiCore & Pkt_Proc;
    .o_addr_2peri           (w_addr_2peri                 ),
    .o_wren_2peri           (w_wren_2peri                 ),
    .o_rden_2peri           (w_rden_2peri                 ),
    .o_wdata_2peri          (w_wdata_2peri                ),
    .o_wstrb_2peri          (w_wstrb_2peri                ),
    .i_rdata_2PBUS          (w_rdata_2PBUS                ),
    .i_ready_2PBUS          (w_ready_2PBUS                ),
    .i_int_2PBUS            (w_int_2PBUS                  ),
    //* Peri interface (for 2 PEs), connected with MultiCore;
    .i_peri_rden            (w_peri_rden                  ),
    .i_peri_wren            (w_peri_wren                  ),
    .i_peri_addr            (w_peri_addr                  ),
    .i_peri_wdata           (w_peri_wdata                 ),
    .i_peri_wstrb           (w_peri_wstrb                 ),
    .o_peri_rdata           (w_peri_rdata                 ),
    .o_peri_ready           (w_peri_ready                 ),
    //* irq interface (for 2 PEs)
    .o_irq                  (w_irq_bitmap                 ),
    .i_irq_ack              (w_irq_ack                    ),
    .i_irq_id               (w_irq_id                     ),
    //* instr/data offset;
    .o_instr_offset_addr    (w_instr_offset_addr          ),
    .o_data_offset_addr     (w_data_offset_addr           ),
    //* start_en;
    .i_start_en_pad         (i_start_en_pad               ),
    .o_start_en             (w_start_en                   ),
    .i_conf_en              (w_conf_en                    ),
    .o_rst_n_AiPE           (                             ),
    //* system_time;
    .i_update_valid         (1'b0                         ),
    .i_update_system_time   (0                            ),
    .o_system_time          (                             ),
    .o_second_pulse         (                             )
  );
  //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>//

  //====================================================================//
  //*   Pkt_Proc_Top
  //====================================================================//
  Pkt_Proc_Top Pkt_Proc_Top(
    //* clk & rst_n;
    .i_sys_clk              (i_sys_clk                    ),
    .i_sys_rst_n            (i_sys_rst_n                  ),
    .i_pe_clk               (i_pe_clk                     ),
    .i_rst_n                (i_rst_n                      ),
    //* To/From CPI, TODO
    .i_pe_conf_mac          (i_pe_conf_mac                ),
    .i_data_valid           (i_data_valid                 ),
    .i_data                 (i_data                       ),
    .o_data_valid           (o_data_valid                 ),
    .o_data                 (o_data                       ),
    .i_meta_valid           (i_meta_valid                 ),
    .i_meta                 (i_meta                       ),
    .o_meta_valid           (o_meta_valid                 ),
    .o_meta                 (o_meta                       ),
    //* ready
    .o_alf                  (o_alf                        ),
    .i_alf                  (i_alf                        ),
    //* for network configuration
    .o_data_conf_valid      (w_data_conf_valid_from_net   ),
    .o_data_conf            (w_data_conf_from_net         ),
    .i_data_conf_valid      (w_data_conf_valid_to_net     ),
    .i_data_conf            (w_data_conf_to_net           ),
    //* Peri interface (DMA, DRA)
      .i_peri_rden          (w_rden_2peri                 ),
      .i_peri_wren          (w_wren_2peri                 ),
      .i_peri_addr          (w_addr_2peri                 ),
      .i_peri_wdata         (w_wdata_2peri                ),
      .i_peri_wstrb         (w_wstrb_2peri                ),
      .o_peri_rdata         (w_rdata_2PBUS                ),
      .o_peri_ready         (w_ready_2PBUS                ),
      .o_peri_int           (w_int_2PBUS                  ),
    //* DRA interface;
    .i_reg_rd               (w_reg_rd                     ),
    .i_reg_raddr            (w_reg_raddr                  ),
    .o_reg_rdata            (w_reg_rdata                  ),
    .o_reg_rvalid           (w_reg_rvalid                 ),
    .o_reg_rvalid_desp      (w_reg_rvalid_desp            ),
    .i_reg_wr               (w_reg_wr                     ),
    .i_reg_wr_desp          (w_reg_wr_desp                ),
    .i_reg_waddr            (w_reg_waddr                  ),
    .i_reg_wdata            (w_reg_wdata                  ),
    .i_status               (w_status_2pktMem             ),
    .o_status               (w_status_2core               ),
    //* DMA interface;
    .o_dma_rden             (w_dma_rden                   ),
    .o_dma_wren             (w_dma_wren                   ),
    .o_dma_addr             (w_dma_addr                   ),
    .o_dma_wdata            (w_dma_wdata                  ),
    .i_dma_rdata            (w_dma_rdata                  ),
    .i_dma_rvalid           (w_dma_rvalid                 ),
    .i_dma_gnt              (w_dma_gnt                    )
  );
  //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>//

  //====================================================================//
  //*   for uart, host can send to fpga anytime;
  //====================================================================//
  assign  o_uart_rts = {`NUM_PE{1'b0}};
  //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>//

endmodule    
